package tp;

public class Liczba {
	/**
	 * Tablica wykorzystywana do mapowania cyfr w roznych systemach liczbowych na system dziesietny
	 */
	private static final char Digits[] = 
		{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
	
	/**
	 * Przechowywana liczba, zapisana w systemie dziesietnym
	 */
	private int n;

	/**
	 * Prawidlowy zapis liczby n w oryginalnie podanym systemie liczbowym
	 */
	private String str;	
	
	/**
	 * Tworzy obiekt przechowujacy liczbe 0.
	 */
	Liczba() {
		this.n = 0;
	}
	
	/**
	 * Tworzy obiekt przechowujacy liczbe n.
	 * 
	 * @param n liczba w zapisie dziesietnym
	 */
	Liczba(int n) {
		this.n = n;
	}
	
	/**
	 * Tworzy obiekt przechowujacy liczbe n.
	 * 
	 * @param n liczba zapisana w systemie liczbowym 2 - 16
	 * @param podstawa system liczbowy uzyty do zapisu liczby n
	 * @throws LiczbaException
	 */
	Liczba(String n, int podstawa) throws LiczbaException {
		n = n.toUpperCase();
				
		if ((podstawa<2) || (podstawa>16))
			throw new LiczbaException("Podstawa systemu musi byc liczba w przedziale 2 - 16.");
		if (n.isEmpty())
			throw new LiczbaException("Nie podano zadnej liczby.");
		
		int stringEnd = n.length()-1;
		int power = 1;
		for (int i=0; i<=stringEnd; i++) {
			char digit = n.charAt(stringEnd-i);
			int value = -1;
			for (int j=0; j<podstawa; j++) {
				if (digit == Digits[j])
					value = j;
			}
			if (value == -1) 
				throw new LiczbaException(n + " nie jest liczba naturalna w systemie " + podstawa + ".");
			else {
				this.n += value * power;
				if ((this.n < 0) || (power <= 0))
					throw new LiczbaException(n + " wykracza poza zakres.");
				power *= podstawa;
			}
		}
		str = zapis(podstawa);
		if (!n.equals(str))
			throw new LiczbaException(n + " nie jest poprawnie zapisana liczba.");
	}
	
	/**
	 * Zwraca zapis przechowywanej liczby w wybranym systemie liczbowym 2 - 16
	 * 
	 * @param podstawa system liczbowy w ktorym nalezy zapisac przechowywana liczbe
	 * @return liczba zapisana w okreslonym systemie liczbowym
	 * @throws LiczbaException
	 */
	public String zapis(int podstawa) throws LiczbaException {
		if ((podstawa<2) || (podstawa>16))
			throw new LiczbaException("Podstawa systemu musi byc liczba w przedziale 2 - 16.");
		
		int n = this.n;
		int digit;
		String zapis = "";
		
		while (n>0) {
			digit = n % podstawa;
			zapis = Digits[digit] + zapis;
			n = n / podstawa;
		}
		
		return zapis;
	}
	
	/**
	 * Zwraca zapis przechowywanej liczby w oryginalnie podanym systemie liczbowym.
	 * 
	 * @return zapis liczby w oryginalnym systemie liczbowym
	 */
	public String getStr() {
		return str;
	}
	
	/**
	 * Klasa testowa wykorzystana do przecwiczenia rzucania wyjatkami
	 * 
	 * @author bartek
	 *
	 */
	public class LiczbaException extends IllegalArgumentException {
		LiczbaException(String s) {
			super(s);
		}
	}	
}
